package storage;

import java.io.File;
import java.io.IOException;
import java.util.*;

import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import entity.*;
import entity.Database.DataType;

public class DataAccessManager 
{
	private static String filePath="data";
	private static String fileName="database.xml";
	
	private List<Database> databaseList;
	public DataAccessManager()
	{
		if (!isDatabaseFileExists()) initDatabaseFile();
		refreshList();
	}
	
	public boolean isDatabaseFileExists()
	{
		File file = new File(filePath+"/"+fileName);
		if (file.exists()) return true;
		else return false;
	}
	
	public int isDatabaseExists(String Name)
	{
		for (int i=0;i<databaseList.size();i++) if (databaseList.get(i).getName().compareTo(Name)==0) return i;
		return -1;
	}
	
	public void refreshList()
	{
		databaseList = loadDatabases();
	}
	
	public void initDatabaseFile()
	{
		 try 
		 {
			 new File(filePath).mkdirs();
			 
			 DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			 DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			 Document doc = docBuilder.newDocument();
			 Element rootElement = doc.createElement("DatabaseServer");
			 doc.appendChild(rootElement);
		 
			 TransformerFactory transformerFactory = TransformerFactory.newInstance();
			 Transformer transformer = transformerFactory.newTransformer();
			 DOMSource source = new DOMSource(doc);
			 StreamResult result = new StreamResult(new File(filePath+"/"+fileName));
		 
			 transformer.transform(source, result);
		 
		 } 
		 catch (ParserConfigurationException pce) 
		 {
			 pce.printStackTrace();
		 } 
		 catch (TransformerException tfe) 
		 {
			 tfe.printStackTrace();
		 }
	}
	
	public List<Database> getDatabaseList()
	{
		return this.databaseList;
	}
	
	public Database getDatabase(int index)
	{
		if (index<0 || index>=databaseList.size()) return null;
		return databaseList.get(index);
	}
	
	public Database getDatabaseByName(String Name)
	{
		int index = isDatabaseExists(Name);
		if (index==-1) return null;
		return databaseList.get(index);
	}
	
	public int getDatabaseListSize()
	{
		return databaseList.size();
	}
	public void saveDatabases()
	{
		saveDatabases(databaseList);
	}
	public void saveDatabases(List<Database> list)
	{
		try 
		 {
			 DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			 DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
			 Document doc = docBuilder.newDocument();
			 Attr attribute;
			 Element rootElement = doc.createElement("DatabaseServer");
			 doc.appendChild(rootElement);
			 
			 for (int i=0;i<list.size();i++)
			 {
				 Database database = list.get(i);
				 Element databaseElement = doc.createElement("Database");
				 
				 attribute = doc.createAttribute("Name");
				 attribute.setValue(database.getName());
				 databaseElement.setAttributeNode(attribute);
				 
				 for (int j=0;j<database.getTablesCount();j++)
				 {
					 Table table = database.getTableAt(j);
					 Element tableElement = doc.createElement("Table");
					 
					 attribute = doc.createAttribute("Name");
					 attribute.setValue(table.getName());
					 tableElement.setAttributeNode(attribute);
					 
					 attribute = doc.createAttribute("PrimaryKey");
					 attribute.setValue(Integer.toString(table.getPrimaryKey()));
					 tableElement.setAttributeNode(attribute);
					 
					 attribute = doc.createAttribute("RowCount");
					 attribute.setValue(Integer.toString(table.getRowCount()));
					 tableElement.setAttributeNode(attribute);
					 
					 for (int k=0;k<table.getColumnsCount();k++)
					 {
						 Column column = table.getColumnAt(k);
						 Element columnElement = doc.createElement("Column");
						
						 attribute = doc.createAttribute("Name");
						 attribute.setValue(column.getName());
						 columnElement.setAttributeNode(attribute);
						 
						 attribute = doc.createAttribute("Type");
						 attribute.setValue(column.getType().toString());
						 columnElement.setAttributeNode(attribute);
						 
						 attribute = doc.createAttribute("IsPrimaryKey");
						 attribute.setValue(Boolean.toString(column.IsPrimaryKey()));
						 columnElement.setAttributeNode(attribute);
						 
						 for (int p=0;p<column.getDataCount();p++)
						 {
							 String data = column.getDataAt(p);
							 Element dataElement = doc.createElement("Data");
							 dataElement.setTextContent(data);
							 columnElement.appendChild(dataElement);
						 }
						
						 tableElement.appendChild(columnElement);
					 }
					 databaseElement.appendChild(tableElement);
				 }
				 rootElement.appendChild(databaseElement);
			 }
		 
			 TransformerFactory transformerFactory = TransformerFactory.newInstance();
			 Transformer transformer = transformerFactory.newTransformer();
			 DOMSource source = new DOMSource(doc);
			 StreamResult result = new StreamResult(new File(filePath+"/"+fileName));
		 
			 transformer.transform(source, result);
		 
		 } 
		 catch (ParserConfigurationException pce) 
		 {
			 JOptionPane.showMessageDialog(null, pce.toString());
		 } 
		 catch (TransformerException tfe) 
		 {
			 JOptionPane.showMessageDialog(null, tfe.toString());
		 }
	}
	private List<Database> loadDatabases()
	{
		List<Database> list = new ArrayList<Database>();
		try 
		{
			DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
	        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
	        Document doc = docBuilder.parse (new File(filePath+"/"+fileName));
	        
	        NodeList databaseList = doc.getElementsByTagName("Database");
	        for (int i=0;i<databaseList.getLength();i++)
	        {
	        	Node databaseNode = databaseList.item(i);
	        	Database database = new Database(databaseNode.getAttributes().getNamedItem("Name").getNodeValue());
	        	NodeList tableList = databaseNode.getChildNodes();
	        	for (int j=0;j<tableList.getLength();j++)
	        	{
	        		Node tableNode = tableList.item(j);
	        		Table table = new Table(tableNode.getAttributes().getNamedItem("Name").getNodeValue());
	        		NodeList columnList = tableNode.getChildNodes();
	        		for (int k=0;k<columnList.getLength();k++)
	        		{
	        			Node columnNode = columnList.item(k);
	        			Column column = new Column();
	        			column.setName(columnNode.getAttributes().getNamedItem("Name").getNodeValue());
	        			column.setType(DataType.valueOf(columnNode.getAttributes().getNamedItem("Type").getNodeValue()));
	        			column.setPrimaryKey(columnNode.getAttributes().getNamedItem("IsPrimaryKey").getNodeValue().compareTo("true")==0);
	        			
	        			NodeList dataList = columnNode.getChildNodes();
	        			for (int p=0;p<dataList.getLength();p++)  column.addData(dataList.item(p).getTextContent());
	        			table.addColumn(column);
	        		}
	        		table.setPrimaryKey(Integer.parseInt(tableNode.getAttributes().getNamedItem("PrimaryKey").getNodeValue()));
	        		table.setRowCount(Integer.parseInt(tableNode.getAttributes().getNamedItem("RowCount").getNodeValue()));
	        		database.addTable(table);
	        	}
	        	list.add(database);
	        }
	        
	        return list;
		}
		catch (SAXException SE)
		{
			return null;
		} 
		catch (ParserConfigurationException e) 
		{
			return null;
		} 
		catch (IOException e) 
		{
			return null;
		}
		
	}
	
	
	public boolean addDatabase(Database newDatabase)
	{
		if (isDatabaseExists(newDatabase.getName())!=-1) return false;
		databaseList.add(newDatabase);
		saveDatabases(databaseList);
		return true;
	}
	
	public boolean renameDatabase(String oldName,String newName)
	{
		int index = isDatabaseExists(oldName);
		if (index==-1) return false;
		if (isDatabaseExists(newName)!=-1) return false;
		databaseList.get(index).setName(newName);
		saveDatabases(databaseList);
		return true;
	}
	
	public boolean deleteDatabaseByName(String Name)
	{
		int index = isDatabaseExists(Name);
		if (index==-1) return false;
		databaseList.remove(index);
		saveDatabases(databaseList);
		return true;
	}

}

